/**
 * Copyright (c) 2016-2019 九点科技 All rights reserved.
 *
 * http://www.9dyun.cn
 *
 * 版权所有，侵权必究！
 */
package com.dian.modules.inv.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.dian.common.utils.*;
import com.dian.common.validator.ValidatorUtils;
import com.dian.common.validator.group.AddGroup;
import com.dian.common.validator.group.UpdateGroup;
import com.dian.modules.enums.inv.InHead_InTypeEnum;
import com.dian.modules.enums.inv.InHead_InStateEnum;
import com.dian.modules.enums.inv.OutHead_OutStateEnum;
import com.dian.modules.inv.entity.*;
import com.dian.modules.inv.poi.vo.GoodsStockExportVO;
import com.dian.modules.inv.poi.vo.InHeadExportVO;
import com.dian.modules.inv.poi.vo.InLineExportVO;
import com.dian.modules.inv.service.GoodsStockService;
import com.dian.modules.inv.vo.GoodsStockVO;
import com.dian.modules.pos.entity.PurchaseHeadEntity;
import com.dian.modules.pos.entity.PurchaseLineEntity;
import com.dian.modules.pos.service.PurchaseHeadService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dian.common.exception.RRException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.apache.commons.collections.CollectionUtils;
import com.dian.common.server.CommonService;
import com.dian.modules.inv.dao.InHeadDao;
import com.dian.modules.inv.service.InHeadService;
import com.dian.modules.inv.service.InLineService;


/**
 * 入库单服务实现类
 *
 * @author xiaolai
 * @email xiaolai@9dyun.cn
 * @date 2019-06-11 00:12:45
 */
@Service("inHeadService")
public class InHeadServiceImpl extends ServiceImpl<InHeadDao, InHeadEntity> implements InHeadService {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private final CommonService commonService;

    @Autowired
    public InLineService inLineService;


    @Autowired
    public PurchaseHeadService purchaseHeadService;

    @Autowired
    public GoodsStockService goodsStockService;


    @Autowired
    public InHeadServiceImpl(CommonService commonService) {
        this.commonService = commonService;
    }

    /**
     * 入库单分页
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<InHeadEntity> page = this.page(new Query<InHeadEntity>().getPage(params),getQueryWrapper(params) );
        return new PageUtils(page);
    }

    /**
    *  入库单新增
    * @param inHeadEntity
    * @return
    */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean saveInfo(InHeadEntity inHeadEntity) {
        //设置月份
        inHeadEntity.setInMonth(new Date().toText2());
        //设置编码  InNo
        inHeadEntity.setInNo(commonService.getCode(InHeadEntity.class));
        //设置时间
        inHeadEntity.setInDate(new DateTime());
        //数据完整性校验
        this.paramsCheck(inHeadEntity,AddGroup.class);

        //校验采购订单数量
        posCheckBaseNum(inHeadEntity);


        //保存主表
        this.save(inHeadEntity);
        //保存从表
        if (CollectionUtils.isNotEmpty(inHeadEntity.getInLineEntityList())) {
            inLineService.updateInfo(inHeadEntity);
        }
        return true;
    }

    /**
     *入库单更新
     * @param inHeadEntity
     * @return
     */
    @Override
    public boolean updateInfo(InHeadEntity inHeadEntity) {
        //修改状态校验
        this.updateCheck(inHeadEntity.getId());
        //主表数据完整性校验
        this.paramsCheck(inHeadEntity, UpdateGroup.class);

        //校验采购订单数量
        posCheckBaseNum(inHeadEntity);

        //更新主表
        this.updateById(inHeadEntity);
        //更新从表
        inLineService.updateInfo(inHeadEntity);
        return true;
    }

    /**
     *入库单删除
     * @param id
     * @return
     */
    @Override
    public boolean deleteInfo(Long id) {
        //删除状态校验
        this.deleteCheck(id);
        //更新从表
        inLineService.deleteInfo(id);
        //更新主表
        this.remove(new QueryWrapper<InHeadEntity>().eq("id",id));
        return true;
    }

    /**
     * 入库单详情
     * @param id
     * @return
     */
    @Override
    public InHeadEntity getInfo(Long id) {
        InHeadEntity inHeadEntity =getById(id);
        List<InLineEntity> lineList=inLineService.queryList(id);
        inHeadEntity.setInLineEntityList(lineList);
        return inHeadEntity;
    }

    /**
     * 入库单审核
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean checkInfo(Long id) {
        InHeadEntity inHeadEntity =this.getInfo(id);
        checkCheck(inHeadEntity);
        //设置入库单状态
        inHeadEntity.setInState(InHead_InStateEnum.AUDITED.getValue());
        inHeadEntity.setCheckDate(new Date());
        inHeadEntity.setInMonth(new Date().toText2());
        inHeadEntity.setCheckUserId(commonService.getUserId());
        inHeadEntity.setCheckUserName(commonService.getUserName());
        this.updateById(inHeadEntity);

        //修改明细入库月份
        inLineService.updateInMonth(id,InHead_InStateEnum.AUDITED.getValue());

        //反写采购订单的已入库数量
        purchaseHeadService.updatePosNum(inHeadEntity);
        //写入实际  库存表
        this.casIncreaseActualStock(inHeadEntity);
        return true;
    }
    /**
     * 入库单导出
     * @param params
     * @return
     */
    @Override
    public List<InHeadExportVO> exportList(Map<String, Object> params) {
        List<InHeadEntity> list = new ArrayList<>();
        if (StrUtil.isEmptyIfStr(params.get("exprotType"))){
            list = this.page(new Query<InHeadEntity>().getPage(params),getQueryWrapper(params)).getRecords();
        } else {
            this.list(getQueryWrapper(params));
        }
        List<InHeadExportVO> resultList = BeanConverter.convertList(list, InHeadExportVO.class);
        if (CollectionUtils.isNotEmpty(resultList)){
            for (InHeadExportVO inHeadExportVO :resultList ) {
                List<InLineEntity> inLineEntities = inLineService.queryList(inHeadExportVO.getId());
                inHeadExportVO.setInLineExportVOList(BeanConverter.convertList(inLineEntities, InLineExportVO.class));
            }
        }
        return resultList;
    }

    /**
     * 其他单据单审核生成入库单
     * @param inHeadEntity
     * @return
     */
    @Override
    public boolean createInHead(InHeadEntity inHeadEntity) {
        //核验数据完整性
        this.paramsCheck(inHeadEntity,AddGroup.class);
        //保存主表数据
        this.save(inHeadEntity);
        //判断明细数据是否为空
        if (CollectionUtils.isNotEmpty(inHeadEntity.getInLineEntityList())){
            //获取明细数据
            List<InLineEntity> inLineEntityList = inHeadEntity.getInLineEntityList();
            ListUtils.setPropertyValue(inLineEntityList,"inId",inHeadEntity.getId());
            //保存明细数据
            inLineService.saveBatch(inLineEntityList);
        }
        return true;
    }



    /***********************************************************************************************/
    /****************************************** 私有方法 ********************************************/
    /***********************************************************************************************/


    private void casIncreaseActualStock(InHeadEntity inHeadEntity){
        if (CollectionUtils.isNotEmpty(inHeadEntity.getInLineEntityList())) {
            //获取明细数据
            List<InLineEntity> inLineEntityList = inHeadEntity.getInLineEntityList();
            for (InLineEntity inLineEntity : inLineEntityList) {
                GoodsStockVO goodsStockVO=BeanConverter.convert(inLineEntity,GoodsStockVO.class);
                logger.debug("增加实际库存 {}", JSON.toJSONString(goodsStockVO));
                goodsStockService.casIncreaseActualStock(goodsStockVO);
            }
        }

    }
    /**
     * 修改状态校验
     *
     * @param
     */
    private void updateCheck(Long id) {
        InHeadEntity inHeadEntity =this.getById(id);
        if (inHeadEntity.getInState().equals(OutHead_OutStateEnum.AUDITED.getValue())){
            throw new RRException(String.format("[%s] 此入库单已审核，禁止修改",inHeadEntity.getInNo()));
        }
    }
    /**
     * 审核状态校验
     *
     * @param
     */
    private void checkCheck(InHeadEntity inHeadEntity) {
        //已审核
        if(inHeadEntity.getInState().equals(OutHead_OutStateEnum.AUDITED.getValue())){
            throw new RRException(String.format("[%s] 此入库单已审核",inHeadEntity.getInNo()));
        }
        posCheckBaseNum(inHeadEntity);
    }

    /**入库新增和修改时，判断采购数据
     *
     * @param inHeadEntity
     */
    private  void posCheckBaseNum(InHeadEntity inHeadEntity){
        //如果是采购入库单，则应该判断入库数量不能超过采购数量
        if(inHeadEntity.getInType().equals(InHead_InTypeEnum.POS.getValue())){
            PurchaseHeadEntity purchaseHeadEntity= purchaseHeadService.getInfo(inHeadEntity.getSourceId());
            if(purchaseHeadEntity==null) {
                throw new RRException(String.format("[%s] 无效的采购入库单", inHeadEntity.getInNo()));
            }
            List<PurchaseLineEntity> posLinelist= purchaseHeadEntity.getPurchaseLineEntityList();
            List<InLineEntity> inLinelist= inHeadEntity.getInLineEntityList();
            if(CollectionUtils.isNotEmpty(posLinelist)){
                inLinelist.forEach(k->{
                    int index = inLinelist.indexOf(k) + 1;
                    posLinelist.forEach(v->{
                        if(k.getGoodsId().equals(v.getGoodsId())){
                            if(v.getBaseNum().compareTo(k.getBaseNum())<0){
                                throw new RRException(String.format("%s 入库基础数量大于采购基础数量", v.getGoodsName()));
                            }
                           /* if(v.getQtyNum().compareTo(k.getQtyNum())<0){
                                throw new RRException(String.format("%s 入库库存数量大于采购库存数量",  v.getGoodsName()));
                            }
                            if(v.getAuxNum().compareTo(k.getAuxNum())<0){
                                throw new RRException(String.format("%s 入库辅助数量大于采购辅助数量",  v.getGoodsName()));
                            }*/
                        }
                    });
                });
            }
        }
    }
    /**
     * 删除状态校验
     *
     * @param
     */
    private void deleteCheck(Long id) {
        InHeadEntity inHeadEntity =this.getById(id);
        if (!inHeadEntity.getInState().equals(InHead_InStateEnum.WAITCHECK.getValue())) {
            throw new RRException(String.format("只允许删除未审核的入库单"));
        }
    }

    /**
     * 新增和修改参数校验
     *
     * @param record
     */
    private void paramsCheck(InHeadEntity record, Class<?> cls) {

        ValidatorUtils.validateEntity(record, cls);
        if (CollectionUtils.isEmpty(record.getInLineEntityList())) {
            throw new RRException("入库单明细数据不能为空");
        }

        ListUtils.setPropertyValue(record.getInLineEntityList(),"warehouseId",record.getWarehouseId());
        ListUtils.setPropertyValue(record.getInLineEntityList(),"warehouseCode",record.getWarehouseCode());
        ListUtils.setPropertyValue(record.getInLineEntityList(),"warehouseName",record.getWarehouseName());
        ListUtils.setPropertyValue(record.getInLineEntityList(),"inMonth",record.getInMonth());
        ListUtils.setPropertyValue(record.getInLineEntityList(),"inState",record.getInState());
        for (InLineEntity inLineEntity : record.getInLineEntityList()) {
            inLineEntity.setGoodsAmount(inLineEntity.getBaseNum().multiply(inLineEntity.getGoodsPrice()));
            int index = record.getInLineEntityList().indexOf(inLineEntity) + 1;
            try {
                ValidatorUtils.validateEntity(inLineEntity, Arrays.asList("inId"),cls);
            }catch (RRException e){
                throw new RRException(String.format("第%s行 入库单明细校验失败<br/>"+e.getMsg(), index));
            }
        }

    }

    /**
     * 获取查询条件
     *
     * @param
     */
    private QueryWrapper<InHeadEntity> getQueryWrapper(Map<String, Object> params) {
        QueryWrapper<InHeadEntity> queryWrapper=new QueryWrapper<>();
        if(!StrUtil.isBlankIfStr(params.get("inNo"))){
            queryWrapper.like("in_no",params.get("inNo"));
        }
        if(!StrUtil.isBlankIfStr(params.get("inDate"))){
            String inDate=String.valueOf(params.get("inDate"));
            String[] inDateRange=inDate.split("至");
            if(inDateRange.length==2){
                queryWrapper.gt("in_date", DateUtils.getBeginTimeOfDate(inDateRange[0]));
                queryWrapper.lt("in_date",DateUtils.getBeginTimeOfDate(inDateRange[1]));
            }else{
                queryWrapper.gt("in_date",DateUtils.getBeginTimeOfDate(inDate));
            }
        }

       /* if(!StrUtil.isBlankIfStr(params.get("warehouseId"))){
            queryWrapper.like("warehouse_id",params.get("warehouseId"));
        }
        if(!StrUtil.isBlankIfStr(params.get("outState"))){
            queryWrapper.like("out_state",params.get("outState"));
        }

        if(!StrUtil.isEmptyIfStr(params.get("propKey"))){
            queryWrapper.and(wrapper -> wrapper);
        }*/
        queryWrapper.orderByDesc("id");
        return queryWrapper;
    }
}
